package xyz.labmem.core.aspect

import kotlinx.coroutines.DelicateCoroutinesApi
import net.bytebuddy.asm.Advice.*
import net.bytebuddy.implementation.bytecode.assign.Assigner
import xyz.labmem.core.annotation.FXRedirect
import xyz.labmem.core.base.FXRedirectParam
import xyz.labmem.core.context.FXApplicationContext
import xyz.labmem.core.reflex.FXBuilder
import java.lang.reflect.Method

/**
 * @Author lty
 * @Date 2021/9/16 11:27
 */
class FXApplicationAspect {

    companion object {

        @JvmStatic
        @OnMethodEnter
        fun onMethodEnter(
            @This target: Any,
            @Origin method: Method,
            @AllArguments args: Array<out Any>?
        ) {
            try {
                //执行切面
                var aspect = getAspect(target.javaClass.simpleName)
                if (aspect != null) {
                    aspect = aspect as BaseFXAspect
                    aspect.before(target, method, args)
                }
            } catch (e: Throwable) {
                afterException(target, method, args, e)
            }
        }

        @OptIn(DelicateCoroutinesApi::class)
        @JvmStatic
        @OnMethodExit
        fun onMethodExit(
            @This target: Any,
            @Origin method: Method,
            @AllArguments args: Array<out Any>?,
            @Return(typing = Assigner.Typing.DYNAMIC) returnVal: Any?
        ) {
            //是否是重定向方法，执行重定向
            val annotation = method.getAnnotation(FXRedirect::class.java)
            if (annotation != null) {
                if (FXRedirectParam::class.java == method.returnType) {
                    if (returnVal != null) {
                        val rev = returnVal as FXRedirectParam
                        rev.redirectController = target
                        FXBuilder.startStage(rev)
                    }
                }
            }
            //执行切面
            var aspect = getAspect(target.javaClass.simpleName)
            if (aspect != null) {
                aspect = aspect as BaseFXAspect
                aspect.after(target, method, args, returnVal)
            }
        }

        fun afterException(target: Any, method: Method, args: Array<out Any>?, e: Throwable?): Boolean {
            //执行切面
            var aspect = getAspect(target.javaClass.simpleName)
            if (aspect != null) {
                aspect = aspect as BaseFXAspect
                return aspect.afterException(target, method, args, e)
            }
            return true
        }

        private fun getAspect(className: String): Any? {
            return FXApplicationContext.aspectBeans[className.split("$")[0]]
        }
    }
}